/**
 * 配置
 * */
package org.zmhhxl.api.auth.domain.entity;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.hibernate.Hibernate;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.io.Serializable;
import java.time.Instant;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

//相当于//配置数据实体，即PO(Persistent Object)
//@JsonIdentityInfo(
//      generator = ObjectIdGenerators.PropertyGenerator.class,
//      property = "id")
//@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
//@JsonDeserialize(using = CustomUserInfoDeserializer.class)
//@NamedEntityGraphs(@NamedEntityGraph(
//      name = "userInfo.userDetails",
//      attributeNodes = {@NamedAttributeNode(value="thirdPartyUser", subgraph = "UserInfo.withThirdPartyUser")},
//
//      subgraphs = {@NamedSubgraph(
//           name = "UserInfo.withThirdPartyUser",
//           attributeNodes = {@NamedAttributeNode("thirdPartyUser")}
//      ),
//
//      }
//))
//@Data
@Entity
@Table(name = "user")
@Getter
@Setter
@RequiredArgsConstructor
@ToString
@JsonIgnoreProperties(ignoreUnknown = true)  //({"authorities", "accountNonExpired", "accountNonLocked", "credentialsNonExpired", "enabled"})
@EntityListeners(AuditingEntityListener.class)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class UserInfo implements Serializable {
   private static final long serialVersionUID = -4968368933210959171L;

   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   private Long id;

   //@JsonProperty
   @Column(name = "username", nullable = false, unique = true)
   private String username;    //用户名,唯一,覆盖掉UserDetails中的username 账号 account;
   //@JsonProperty
   @Column(name = "password", nullable = false)
   private String password;   //密码，需加密，覆盖掉UserDetails中的password
   //@JsonProperty
   @Column(name = "email", nullable = false, unique = true)
   private String email;
   //@JsonProperty
   private String phone;   //手机号 mobile;
   //@JsonProperty
   @Column(name = "nick_name", nullable = false)
   private String nickName;     //用户的昵称, 用户名、昵称
   //@JsonProperty
   @Column(name = "real_name")
   private String realName;
   @Column(name="avatar_url")
   private String avatarUrl;  //头像地址
   //@JsonProperty
   private Integer gender;
   //@JsonProperty
   private String birthday;
   //@JsonProperty
   private String description;
   //@JsonProperty
   private String address;
   //@JsonProperty
   @Column(name = "enabled", nullable = false, columnDefinition = "tinyint default 1")
   private boolean enabled;  //是否启用,是否已删除

   /**
    * 用户来源
    */
//   @Column(name = "source_from")
//   private String sourceFrom;

   //@JsonProperty
   @CreatedDate
   @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
   private Instant createTime;

   @LastModifiedDate
   @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
   private Instant updateTime;

   //@JsonManagedReference  //避免循环 用于父对象
   //@JsonBackReference
   @OneToMany(targetEntity = ThirdPartyUser.class,
         cascade = CascadeType.ALL,
         fetch = FetchType.LAZY)
   @JoinTable(name = "user_mtm_third_party",
         joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
         inverseJoinColumns = @JoinColumn(name = "third_party_user_id", referencedColumnName = "id"))
   @Fetch(FetchMode.JOIN)
   @ToString.Exclude   //排除
   @JsonProperty("thirdPartyUsers")
   private Set<ThirdPartyUser> thirdPartyUsers = Collections.emptySet();

   //@JsonManagedReference  //避免循环 用于父对象, 子对象用@JsonBackReference
   //@JsonIgnoreProperties(ignoreUnknown = true)  //避免循环
   //对应实现授权角色
   @ManyToMany(targetEntity = Role.class,
         cascade = CascadeType.ALL,
         fetch = FetchType.LAZY
          )
   @JoinTable(name = "user_mtm_role",
         joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
         inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"))
   @Fetch(FetchMode.JOIN)
   @ToString.Exclude //排除
   @JsonProperty("authorities")
   private Set<Role> authorities =  new HashSet<>(); //Collections.emptySet(); Set->Collection 覆盖掉UserDetails中的authorities

   public UserInfo(Long id, String username, String password, boolean enabled, String phone, String email, String avatarUrl, String realName, String nickName, Integer gender, String address, String birthday, String description,  Set<Role> authorities) {
         this.id = id;
         this.username = username;
         this.password = password;
         this.enabled = enabled;
         this.phone = phone;
         this.email = email;
         this.avatarUrl = avatarUrl;
         this.realName = realName;
         this.nickName = nickName;
         this.gender = gender;
         this.address = address;
         this.birthday = birthday;
         this.description = description;
         this.updateTime = Instant.now();  //创建时间 LocalDateTime.now()表示本地日期和时间，不带时区信息, Instant.now()表示精确的时间戳，基于 UTC 时区
         this.authorities = authorities;
   }
   //Collection<? extends GrantedAuthority> getAuthorities();

   //对应实现授权角色, 含mappedBy就不应该有@JoinTable或@JoinColumn
//   @ManyToMany(targetEntity = Role.class,
//         fetch = FetchType.EAGER,   //.LAZY
//         mappedBy = "userInfos")

   // Getters and setters

   @Override
   public boolean equals(Object o) {
      if (this == o) return true;
      if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false;
      UserInfo userInfo = (UserInfo) o;
      return id != null && Objects.equals(id, userInfo.id);
   }

   @Override
   public int hashCode() {
      return getClass().hashCode();
   }


}
